package org.sraosha.framework.util;

import com.alibaba.fastjson.JSON;
import com.google.common.base.Strings;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
import javax.net.ssl.*;
import java.io.*;
import java.net.*;
import java.nio.charset.Charset;
import java.security.cert.X509Certificate;
import java.util.*;

/**
 * @desc   通用http发送方法
 */
public class HttpUtils {
    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
    public static final String APPLICATION_ATOM_XML_VALUE = "application/atom+xml";
    public static final String APPLICATION_FORM_URLENCODED_VALUE = "application/x-www-form-urlencoded";
    public static final String APPLICATION_JSON_VALUE = "application/json";
    public static final String APPLICATION_JSON_UTF8_VALUE = "application/json;charset=UTF-8";
    public static final String APPLICATION_OCTET_STREAM_VALUE = "application/octet-stream";
    public static final String APPLICATION_PDF_VALUE = "application/pdf";
    public static final String APPLICATION_XHTML_XML_VALUE = "application/xhtml+xml";
    public static final String APPLICATION_XML_VALUE = "application/xml";
    public static final String IMAGE_GIF_VALUE = "image/gif";
    public static final String IMAGE_JPEG_VALUE = "image/jpeg";
    public static final String IMAGE_PNG_VALUE = "image/png";
    public static final String MULTIPART_FORM_DATA_VALUE = "multipart/form-data";
    public static final String TEXT_HTML_VALUE = "text/html";
    public static final String TEXT_MARKDOWN_VALUE = "text/markdown";
    public static final String TEXT_PLAIN_VALUE = "text/plain";
    public static final String TEXT_XML_VALUE = "text/xml";
    private static final String PARAM_QUALITY_FACTOR = "q";
    /**
     * 向指定 URL 发送GET方法的请求
     * @param url 发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。可为空
     * @return 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param, String tokenStr) {
        StringBuilder result = new StringBuilder();
        BufferedReader in = null;
        try {
            String urlNameString = url + "?" + param;
            if(StringUtils.isEmpty(param)){
                urlNameString = url;
            }
//            log.info("sendGet - {}", urlNameString);
            URL realUrl = new URL(urlNameString);
            URLConnection connection = realUrl.openConnection();
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            if(!StringUtils.isEmpty(tokenStr)){
                connection.setRequestProperty("Authorization", tokenStr);
            }
            connection.connect();
            in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
//            log.info("recv - {}", result);
        } catch (ConnectException e) {
            e.printStackTrace();
//            log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
        } catch (SocketTimeoutException e) {
            e.printStackTrace();
//            log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
        } catch (IOException e) {
            e.printStackTrace();
//            log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
        } catch (Exception e) {
            e.printStackTrace();
//            log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
//                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.toString();
    }
    /**
     * 向指定 URL 发送POST方法的请求
     * @param url 发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @param token 登录用户token
     * @return 所代表远程资源的响应结果
     */
    public static String erpSendPost(String url, String param, String token) {
        PrintWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        try {
            if(!Strings.isNullOrEmpty(param)){
                url = url + "/" + param;
            }
            //log.info("sendPost - {}", url);
            URL realUrl = new URL(url);
            URLConnection conn = realUrl.openConnection();
            conn.setRequestProperty("Authorization","Bearer "+token);
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setRequestProperty("Accept-Charset", "utf-8");
            conn.setRequestProperty("contentType", "utf-8");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            out = new PrintWriter(conn.getOutputStream());
            out.print(param);
            out.flush();
            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
//            log.info("recv - {}", result);
        } catch (ConnectException e) {
            e.printStackTrace();
//            log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
        } catch (SocketTimeoutException e) {
            e.printStackTrace();
//            log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
        } catch (IOException e) {
            e.printStackTrace();
//            log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
        } catch (Exception e) {
            e.printStackTrace();
//            log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
//                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.toString();
    }

    /**
     * 向指定 URL 发送POST方法的请求
     * @param url   发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendPost(String url, String param) {
        // 获得Http客户端
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        // 创建Post请求
        HttpPost httpPost = new HttpPost(url);
        StringEntity entity = new StringEntity(param, "UTF-8");
        // post请求是将参数放在请求体里面传过去的;这里将entity放入post请求体中
        httpPost.setEntity(entity);
        httpPost.setHeader("Content-Type", "application/json;UTF-8");
        // 响应模型
        CloseableHttpResponse response = null;
        String result = null;
        try {
            // 由客户端执行(发送)Post请求
            response = httpClient.execute(httpPost);
            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();
            result = EntityUtils.toString(responseEntity);
//            log.info("recv - {}", result);
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 释放资源
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 向ERP的登录接口 发送POST方法的请求
     * @param url   发送请求的 URL
     * @param jsonString 请求参数。
     * @return 所代表远程资源的响应结果
     */
    public static String doPostTestTwo(String url, String jsonString) throws IOException {
        // 获得Http客户端
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        // 创建Post请求
        HttpPost httpPost = new HttpPost(url);
        // 将Object转换为json字符串
//        String jsonString = JSON.toJSONString(usersVo);
        StringEntity entity = new StringEntity(jsonString, "UTF-8");
        // post请求是将参数放在请求体里面传过去的;这里将entity放入post请求体中
        httpPost.setEntity(entity);
        httpPost.setHeader("Content-Type", "application/json;UTF-8");
        // 响应模型
        CloseableHttpResponse response = null;
        String token = null;
        try {
            // 由客户端执行(发送)Post请求
            response = httpClient.execute(httpPost);
            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();
            token = EntityUtils.toString(responseEntity);
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 释放资源
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return token;
    }






    /**
     * 向指定 URL 发送POST方法的请求
     * @param url   发送请求的 URL
     * @param object 请求参数。
     * @return 所代表远程资源的响应结果
     */
    public static String sendPostJson(String url,Object object){
        // 获得Http客户端
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        // 创建Post请求
        HttpPost httpPost = new HttpPost(url);
        // 将Object转换为json字符串
        String jsonString = JSON.toJSONString(object);
        StringEntity entity = new StringEntity(jsonString, "UTF-8");
        // post请求是将参数放在请求体里面传过去的;这里将entity放入post请求体中
        httpPost.setEntity(entity);
        httpPost.setHeader("Content-Type", "application/json;UTF-8");
        // 响应模型
        CloseableHttpResponse response = null;
        String result = null;
        try {
            // 由客户端执行(发送)Post请求
            response = httpClient.execute(httpPost);
            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();
            result = EntityUtils.toString(responseEntity,"utf-8");
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 释放资源
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 向指定 URL 发送POST方法的请求
     * @param url   发送请求的 URL
     * @param object 请求参数。
     * @param token 秘钥。
     * @return 所代表远程资源的响应结果
     */
    public static String sendPostJson(String url,Object object,String token){
        // 获得Http客户端
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        // 创建Post请求
        HttpPost httpPost = new HttpPost(url);
        // 将Object转换为json字符串
        String jsonString = JSON.toJSONString(object);
        StringEntity entity = new StringEntity(jsonString, "UTF-8");
        // post请求是将参数放在请求体里面传过去的;这里将entity放入post请求体中
        httpPost.setEntity(entity);
        httpPost.setHeader("Content-Type", "application/json;UTF-8");
        httpPost.setHeader("Authorization","Bearer "+token);
        // 响应模型
        CloseableHttpResponse response = null;
        String result = null;
        try {
            // 由客户端执行(发送)Post请求
            response = httpClient.execute(httpPost);
            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();
            result = EntityUtils.toString(responseEntity,"utf-8");
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 释放资源
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }




    public static String sendSSLPost(String url, String param) {
        StringBuilder result = new StringBuilder();
        String urlNameString = url + "?" + param;
        try {
//            log.info("sendSSLPost - {}", urlNameString);
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());
            URL console = new URL(urlNameString);
            HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setRequestProperty("Accept-Charset", "utf-8");
            conn.setRequestProperty("contentType", "utf-8");
            conn.setDoOutput(true);
            conn.setDoInput(true);

            conn.setSSLSocketFactory(sc.getSocketFactory());
            conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
            conn.connect();
            InputStream is = conn.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String ret = "";
            while ((ret = br.readLine()) != null) {
                if (ret != null && !ret.trim().equals("")) {
                    result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8"));
                }
            }
//            log.info("recv - {}", result);
            conn.disconnect();
            br.close();
        } catch (ConnectException e) {
            e.printStackTrace();
//            log.error("调用 HttpUtils.sendSSLPost ConnectException, url = " + url + ",param = " + param, e);
        } catch (SocketTimeoutException e) {
            e.printStackTrace();
//            log.error("调用 HttpUtils.sendSSLPost SocketTimeoutException, url = " + url + ", param = " + param, e);
        } catch (IOException e) {
            e.printStackTrace();
//            log.error("调用 HttpUtils.sendSSLPost IOException, url = " + url + ", param = " + param, e);
        } catch (Exception e) {
            e.printStackTrace();
//            log.error("调用 HttpsUtil.sendSSLPost Exception, url = " + url + ", param = " + param, e);
        }
        return result.toString();
    }

    private static class TrustAnyTrustManager implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[]{};
        }
    }

    private static class TrustAnyHostnameVerifier implements HostnameVerifier {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }



    /**
     * post
     *
     * @param url
     * @param param
     * @return
     */
    public static String doPost(String url, Map<String, String> param) {
        return executePost(url, map2PostEntity(param), APPLICATION_FORM_URLENCODED_VALUE);
    }


    /**
     * post
     *
     * @param url
     * @param param
     * @param headers
     * @return
     */
    public static String doPost(String url, Map<String, String> param, Map<String, String> headers) {
        return executePost(url, map2PostEntity(param), APPLICATION_FORM_URLENCODED_VALUE, headers);
    }

    /**
     * post
     *
     * @param url
     * @param param
     * @return
     */
    public static String doPostWithJson(String url, Object param, Map<String, String> headers) {
        return executePost(url, obj2PostJsonEntity(param), APPLICATION_JSON_UTF8_VALUE, headers);
    }

    /**
     * post 请求类型
     * @param url
     * @param param
     * @param headers
     * @param contentType
     * @return
     */
    public static String doPostWithJson(String url, Object param, Map<String, String> headers ,String contentType) {
        return executePost(url, obj2PostJsonEntity(param), contentType, headers);
    }

    /**
     * post 请求类型
     * @param url
     * @param param
     * @param headers
     * @param contentType
     * @return
     */
    public static String doPostJson(String url, String param, Map<String, String> headers ,String contentType) {
        return executePost(url, new StringEntity(param, "utf-8"), contentType, headers);
    }

    /**
     * object转为 postEntity with Json
     *
     * @param object
     * @return
     * @throws Exception
     */
    public static StringEntity obj2PostJsonEntity(Object object) {
        return new StringEntity(JSON.toJSONString(object), "utf-8");
    }
    /**
     * 发送post请求
     *
     * @param url
     * @param entity
     * @param contentType
     * @return
     */
    public static String executePost(String url, HttpEntity entity, String contentType) {
        return executePost(HttpClients.createDefault(), url, entity, contentType, null);
    }

    /**
     * 发送带请求头post请求
     *
     * @param url
     * @param entity
     * @param contentType
     * @return
     */
    public static String executePost(String url, HttpEntity entity, String contentType, Map<String, String> headers) {
        return executePost(HttpClients.createDefault(), url, entity, contentType, headers);
    }

    public static String executePost(CloseableHttpClient httpClient,
                                     String url,
                                     HttpEntity entity,
                                     String contentType,
                                     Map<String, String> headers) {

        return executePost(httpClient, url, entity, contentType, headers, Charset.forName("utf-8"));
    }


    public static String executePost(CloseableHttpClient httpClient,
                                     String url,
                                     HttpEntity entity,
                                     String contentType,
                                     Map<String, String> headers,
                                     Charset responseCharset) {

        String data = "";
        HttpPost httpPost = new HttpPost();
        CloseableHttpResponse response = null;
        try {
            httpPost.setURI(new URI(url));
            httpPost.setHeader(HttpHeaders.CONTENT_TYPE, contentType);
            if (null != headers) {
                headers.entrySet().forEach(e -> {
                    httpPost.setHeader(e.getKey(), e.getValue());
                });
            }
            httpPost.setEntity(entity);
            try {
                response = httpClient.execute(httpPost);
                HttpEntity responseEntity = response.getEntity();
                if (responseEntity != null) {
                    data = EntityUtils.toString(responseEntity, responseCharset);
                }
            } finally {
                if (response != null) {
                    response.close();
                }
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // 关闭连接,释放资源
            try {
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return data;
    }
    /**
     * get
     *
     * @param url
     * @param param
     * @return
     */
    public static String doGet(String url, Map<String, String> param) {
        return executeGet(url + map2ParamGet(param,true), null);
    }


    /**
     * get
     *
     * @param url
     * @param param
     * @return
     */
    public static String doGet(String url, Map<String, String> param, Map<String, String> headers) {
        return executeGet(url +  map2ParamGet(param,true), headers);
    }


    /**
     * get
     *
     * @param url
     * @return
     */
    public static String doGet(String url) {
        return executeGet(url, null);
    }

    /**
     * 发送get 请求
     *
     * @param url
     * @return
     */
    public static String executeGet(String url,
                                    Map<String, String> headers) {
        String data = "";
        HttpGet httpGet = new HttpGet();
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            httpGet.setURI(new URI(url));

            if (null != headers) {
                headers.entrySet().forEach(e -> {
                    httpGet.setHeader(e.getKey(), e.getValue());
                });
            }
            try {
                response = httpClient.execute(httpGet);
                HttpEntity responseEntity = response.getEntity();
                if (responseEntity != null) {
                    data = EntityUtils.toString(responseEntity, "UTF-8");
                }
            } finally {
                if (response != null) {
                    response.close();
                }
            }

        } catch (Exception e) {
            throw new RuntimeException(e);

        } finally {
            // 关闭连接,释放资源
            try {
                httpClient.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return data;
    }

    /**
     *  map转为 get param
     *
     * @param params
     * @param isUrlEncoder
     * @return
     */
    public static String map2ParamGet(Map<String, String> params, boolean isUrlEncoder) {
        boolean first = true;

        StringBuilder sb = new StringBuilder();
        if (params != null) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                if (first) {
                    sb.append("?");
                } else {
                    sb.append("&");
                }

                sb.append(entry.getKey());
                sb.append("=");
                String value = entry.getValue();
                try {
                    if (StringUtils.isNotEmpty(value)) {
                        if (isUrlEncoder) {
                            sb.append(URLEncoder.encode(value, "UTF-8"));
                        } else {
                            sb.append(value);
                        }
                    }
                } catch (UnsupportedEncodingException e) {
                    throw new RuntimeException("URLEncoder error  please check it.");
                }
                first = false;
            }
        }
        return sb.toString();
    }

    /**
     * map转为 postEntity
     *
     * @param params
     * @return
     */
    public static UrlEncodedFormEntity map2PostEntity(Map<String, String> params) {
        return map2PostEntity(params, "utf-8");
    }

    /**
     * map转为 postEntity
     *
     * @param params
     * @return
     */
    public static UrlEncodedFormEntity map2PostEntity(Map<String, String> params, String charset) {

        List<NameValuePair> nvps = new ArrayList<NameValuePair>();

        if(null != params){
            Set<String> keys = params.keySet();
            for (String key : keys) {
                nvps.add(new BasicNameValuePair(key, params.get(key)));
            }
        }

        try {
            return new UrlEncodedFormEntity(nvps, charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("URLEncoder error  please check it.");
        }

    }


    /**
     * 文件下载到指定路径
     *
     * @param urlString 链接
     * @throws Exception
     */
    public static byte[] downloadPicture(String urlString) throws IOException {
        // 构造URL
        URL url = new URL(urlString);
        // 打开连接
        URLConnection con = url.openConnection();
        //设置请求超时为20s
        con.setConnectTimeout(20 * 1000);
        try (InputStream in = con.getInputStream();
             ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            //创建缓冲区
            byte[] buff = new byte[1024];
            int n;
            // 开始读取
            while ((n = in.read(buff)) >= 0) {
                os.write(buff, 0, n);
            }
            return os.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}